from ma.commons.core.abstractreducer import AbstractReducer


class Reduce(AbstractReducer):
    """This class is normal summer reduce / or in other words a frequency
    count reduce
    """
    
    def __init__(self, key, key_file, key_value_dict, user_vars):     
        """
        """
        
        AbstractReducer.__init__(self, key, key_file, key_value_dict)
        
        # set the user variables
        self.change_margin = user_vars[0]
        self.if_changed = user_vars[1]
        self.input_compute_buffer = user_vars[3]
        
    
    def reduce(self, key, key_file):
        """key is the key being reduced and list of values is the 
        lists within a list that need of be reduced for that key
        if len(list_of_values) is one 
        this reduce counts frequency of key  over the list_of_values
        """
        
        max = -99999999999
        self.frequency_count = 0
        
        prv_num_str = ''
        
        # load data from files and add
        fd = open(key_file, 'r')
        data = fd.read(self.input_compute_buffer)
        while data != '':
            # if number broken from previous, connect here
            if prv_num_str != '' and data[0].isdigit():
                data = prv_num_str + data
            else:
                data = prv_num_str + ',' + data
            
            # convert to list of integers
            list_of_values = [ int(i) for i in data.split(',') if i.strip().isdigit() ]
            
            if len(list_of_values) > 0:
                # cater for last digit and carry over if no divider found
                if data[-1].isdigit():
                    prv_num_str = str(list_of_values[-1])
                    del list_of_values[-1]
                else:
                    prv_num_str = ''
                     
                # now sum all the values collected
                for i in list_of_values:
                    self.frequency_count += i
                    if i > max:
                        max = i
                    
            data = fd.read(self.input_compute_buffer)
        
        # if there is any remaining number
        if prv_num_str != '':
            i = int(prv_num_str)
            self.frequency_count += i
            if i > max:
                max = i
        
        fd.close()
        
        value = [self.frequency_count]
        self.emit(key, value)
        
        # user calls the if changed function to see if the value has changed 
        # significantly of the key in question, if a change margin is given
        if self.change_margin != None:
            self.if_changed[0] = self.check_if_changed(max, value[0], self.change_margin)


    def check_if_changed(self, max, final_value, margin):
        """This function checks if the value has changed more than a given
        margin. This is done by seeing if the maximum value input is within
        the supplied margin from the final value
        """
        
        # if the xml provided no margin value, then the code supposes that
        # the value has always changes during the computation
        if margin == None:
            return True
        
        change = float(max) * margin 
        min_val_allowed = max - change
        max_val_allowed = max + change
        if final_value > max_val_allowed or final_value < min_val_allowed:
            return True
        else:
            return False
        